home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v16n10 / embedcp.exe / CODE.EXE / MACHINE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-28  |  8.9 KB  |  314 lines

  1. // MIOTDREM - Execution support
  2. // ----------------------------
  3. //
  4. // Copyright (c) 1991, Stuart G. Phillips.  All rights reserved.
  5. //
  6. // Permission is granted for non-commercial use of this software.
  7. // You are expressly prohibited from selling this software in any form,
  8. // distributing it with another product, or removing this notice.
  9. // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  10. // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  11. // WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12. // PURPOSE.
  13. //
  14. // This module contains the execution support routines for MIOTDREM.
  15. // The routines deal with the machine level of the V40 such as handling
  16. // breakpoint and other interrupts, reading and writing registers, and
  17. // controlling program execution
  18. //
  19. //
  20.  
  21. // Make sure compiler invokes TASM to assemble our inline code
  22.  
  23. #pragma inline
  24.  
  25. #include "miotdr.h"
  26. #include "mio.h"
  27.  
  28. // Static procedure templates
  29.  
  30. static int mc_run();
  31.  
  32.  
  33. // Local storage for CPU state
  34.  
  35. struct cpu cpu = {  {0,0,0,0,0,0,0,0} ,     // EAX, EBX, ECX, EDX
  36.                     0x00f0, 0,              // SP, ESP
  37.                     0,0,0,0,0,0,            // EBP, ESI, EDI
  38.                     {0},                    // Flags
  39.                     0x100, 0,               // IP, CS
  40.                     0,0,0,0,0               // DS, SS, ES, FS, GS
  41.                  };
  42.  
  43. void read_regs()
  44. {
  45.     send((unsigned char *)&cpu,sizeof(struct cpu));
  46. }
  47.  
  48.  
  49. void write_regs(struct cpu *regs)
  50. {
  51.     unsigned char *s = (unsigned char *) regs;
  52.     unsigned char *d = (unsigned char *) &cpu;
  53.  
  54.     for (int i = 0;i < sizeof(struct cpu);i++)
  55.         *d++ = *s++;
  56.  
  57.     send_ack();
  58. }
  59.  
  60.  
  61. int go_program()
  62. {
  63.     return(mc_run());
  64. }
  65.  
  66.  
  67.  
  68. // Machine assist procedures
  69. // =========================
  70. //
  71. // The following low level procedures provide the context switching
  72. // between MIOTDREM and the program under test.
  73. //
  74.  
  75.  
  76. // Local storage for MIOTDREM stack on context switch
  77.  
  78. static unsigned int saved_ss, saved_sp;
  79.  
  80.  
  81. // mc_run()
  82. //
  83. // This procedure transfers control to the program under test according
  84. // to the registers saved in struct cpu cpu.  A return from the program
  85. // under test to MIOTDREM occurs whenever a breakpoint is hit, a single
  86. // step cycle is executed or a STOP message is received over the serial
  87. // link.  In all cases control is passed back to MIOTDREM by simulating
  88. // a return from mc_run() as invoked in go_program() above.
  89. //
  90. // The return code in AX is used to determine what caused control to be
  91. // returned to MIOTDREM.  The value is passed back to TD by tdrproc().
  92.  
  93. static int mc_run()
  94. {
  95.     // For now - set the three interrupt vectors each time we run
  96.     // the program under test
  97.  
  98.     setvect(0x00,(void interrupt(far *)())mc_brk0);
  99.     setvect(0x01,(void interrupt(far *)())mc_brk1);
  100.     setvect(0x03,(void interrupt(far *)())mc_brk3);
  101.  
  102.     // Push our local machine state onto MIOTDREM stack for later
  103.     // recovery and save our stack (S.O.S)
  104.  
  105.     asm {   push    es;
  106.             pushf;
  107.             mov     saved_ss,ss;
  108.             mov     saved_sp,sp;
  109.         };
  110.  
  111.     // Start restoring the registers for the program under test
  112.  
  113.     asm {   mov     ax,word ptr cpu.g_regs.w.uax;
  114.             mov     bx,word ptr cpu.g_regs.w.ubx;
  115.             mov     cx,word ptr cpu.g_regs.w.ucx;
  116.             mov     dx,word ptr cpu.g_regs.w.udx;
  117.             mov     si,word ptr cpu.usi;
  118.             mov     di,word ptr cpu.udi;
  119.             mov     bp,word ptr cpu.ubp;
  120.             mov     es,word ptr cpu.ues;
  121.  
  122.             cli;                            // Disable interrupts
  123.             mov     ss,word ptr cpu.uss;
  124.             mov     sp,word ptr cpu.usp;
  125.             sti;
  126.  
  127.             push    word ptr cpu.flags;
  128.             push    word ptr cpu.segment;
  129.             push    word ptr cpu.offset;    // Values pushed for iret
  130.  
  131.             mov     ds,word ptr cpu.uds;
  132.             iret;                           // Return to program under test
  133.         };
  134.         return(0);                          // Keep the compiler happy
  135. }
  136.  
  137.  
  138. void mc_return()
  139. {
  140.     // Discard the pushed registers created by the entry code
  141.  
  142.     asm {   pop     di;
  143.             pop     si;
  144.             pop     bp;
  145.     };
  146.  
  147.     // Save original DS and DX, then restore our local DGROUP
  148.  
  149.     asm {   push    dx;
  150.             push    ds;
  151.             mov     dx,DGROUP;
  152.             mov     ds,dx;
  153.     };
  154.  
  155.     // Save state in local struct cpu cpu
  156.  
  157.     asm {   mov     word ptr cpu.udi,di;
  158.             mov     word ptr cpu.usi,si;
  159.             pop     word ptr cpu.uds;
  160.             mov     word ptr cpu.ues,es;
  161.             pop     word ptr cpu.g_regs.w.udx;
  162.  
  163.             // Discard return from mc_return()
  164.  
  165.             pop     dx;             // *JUNK*
  166.             pop     dx;             // *JUNK*
  167.  
  168.             mov     word ptr cpu.g_regs.w.ucx,cx;
  169.             mov     word ptr cpu.g_regs.w.ubx,bx;
  170.             pop     word ptr cpu.g_regs.w.uax;
  171.             pop     word ptr cpu.ubp;
  172.  
  173.             pop     word ptr cpu.offset;
  174.             pop     word ptr cpu.segment;
  175.             pop     word ptr cpu.flags;
  176.  
  177.         };
  178.  
  179.     // Save current stack and swap back to MIOTDREM local stack
  180.  
  181.     asm {   mov     word ptr cpu.uss,ss;
  182.             mov     word ptr cpu.usp,sp;
  183.  
  184.             cli;                    // Disable interrupts
  185.             mov     ss,word ptr saved_ss;
  186.             mov     sp,word ptr saved_sp;
  187.             sti;
  188.  
  189.             // AX contains the reason for return
  190.             // Restore registers pushed on the stack by mc_run() explicitly
  191.  
  192.             popf;
  193.             pop     es;
  194.  
  195.             // Registers pushed on the stack by entry to mc_run() are
  196.             // restored by our exit code
  197.         };
  198. }
  199.  
  200.  
  201. // mc_brk3()
  202. //
  203. // This procedure us the interrupt handler for breakpoint instructions.
  204. // It calls mc_return() to transfer control from the program under test
  205. // back to MIOTDREM
  206.  
  207. void mc_brk3()
  208. {
  209.     asm {   push    ax;             // Save AX
  210.             mov     ax,TD_BRK3;     // Reason for return
  211.     };
  212.  
  213.     mc_return();
  214. }
  215.  
  216. // mc_brk1()
  217. //
  218. // This procedure is the interrupt handler for single step instructions.
  219. // It calls mc_return() to transfer control from the program under test
  220. // back to MIOTDREM
  221. //
  222.  
  223.  
  224. void mc_brk1()
  225. {
  226.     asm {   push    ax;             // Save AX
  227.             mov     ax,TD_BRK1;     // Reason for return
  228.     };
  229.  
  230.     mc_return();
  231. }
  232.  
  233.  
  234.  
  235. // mc_brk0()
  236. //
  237. // This procedure is the interrupt handler for divide by zero interrupts.
  238. // It calls mc_return() to transfer control from the program under test
  239. // back to MIOTDREM
  240.  
  241. void mc_brk0()
  242. {
  243.     asm {   push    ax;             // Save AX
  244.             mov     ax,TD_BRK0;     // Reason for return
  245.     };
  246.  
  247.     mc_return();
  248. }
  249.  
  250.  
  251. // mc_stop()
  252. //
  253. // This procedure is invoked from the serial link interrupt handler if
  254. // a stop packet is detected.  We clean up the stack from the previous
  255. // serial link interrupt and save the state of the program under test
  256. // as it was when the serial link interrupt occurred.  Control is then
  257. // transferred back to MIOTDREM.
  258. //
  259.  
  260.  
  261. void mc_stop()
  262. {
  263.     // We're not going to return to our caller (scc_int) - the return from
  264.     // this routine is made to look like a return from mc_run().
  265.  
  266.     // Firstly undo the effects of the call that got us here
  267.  
  268.     asm {   pop     di;             // Restore pushed registers
  269.             pop     si;
  270.             pop     bp;
  271.             mov     sp,bp;          // Collapse the stack frame belonging
  272.                                     // to scc_int.  This also junks the
  273.                                     // return from mc_stop.
  274.         };
  275.  
  276.     // The stack now looks like it did on entry to scc_int().
  277.     // Save state in local struct cpu cpu by pop'ing the stack
  278.  
  279.     asm {   pop     word ptr cpu.ubp;
  280.             pop     word ptr cpu.udi;
  281.             pop     word ptr cpu.usi;
  282.             pop     word ptr cpu.uds;
  283.             pop     word ptr cpu.ues;
  284.             pop     word ptr cpu.g_regs.w.udx;
  285.             pop     word ptr cpu.g_regs.w.ucx;
  286.             pop     word ptr cpu.g_regs.w.ubx;
  287.             pop     word ptr cpu.g_regs.w.uax;
  288.             pop     word ptr cpu.offset;
  289.             pop     word ptr cpu.segment;
  290.             pop     word ptr cpu.flags;
  291.         };
  292.  
  293.     // Save current stack and swap back to MIOTDREM local stack
  294.  
  295.     asm {   mov     word ptr cpu.uss,ss;
  296.             mov     word ptr cpu.usp,sp;
  297.  
  298.             cli;                    // Disable interrupts
  299.             mov     ss,word ptr saved_ss;
  300.             mov     sp,word ptr saved_sp;
  301.             sti;
  302.  
  303.             mov     ax,TD_KEYINTR;  // Why we returned as return code
  304.  
  305.             // Restore registers pushed on the stack by mc_run() explicitly
  306.  
  307.             popf;
  308.             pop     es;
  309.  
  310.             // Registers pushed on the stack by entry to mc_run() are
  311.             // restored by our exit code
  312.         };
  313. }
  314.